package com.yyfax.account.service;

import com.google.common.collect.Lists;
import com.jaws.core.common.log.Log;
import com.jaws.core.common.util.DateUtil;
import com.jaws.core.compatible.enums.YesNoEnum;
import com.yyfax.account.common.enums.TableSequenceEnum;
import com.yyfax.account.common.exception.AccountExceptionCode;
import com.yyfax.account.common.util.CommonIdUtils;
import com.yyfax.account.dao.AccountFlowDao;
import com.yyfax.account.dao.AccountInfoDao;
import com.yyfax.account.dao.AccountLogDao;
import com.yyfax.account.dao.AccountTradeDao;
import com.yyfax.account.domain.AccountInfo;
import com.yyfax.account.vo.AccountInfoVO;
import com.yyfax.account.vo.BatchOpenAccountReq;
import com.yyfax.account.vo.OpenAccountReq;
import com.yyfax.account.vo.OpenAccountRsp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

@Service
public class AccountInfoServiceImpl implements AccountInfoService {
	private Logger logger = LoggerFactory.getLogger(getClass());

	@Resource
	private AccountInfoDao accountInfoDao;

	@Resource
	private AccountTradeDao accountOrderDao;

	@Resource
	private AccountLogDao accountLogDao;

	@Resource
	private AccountFlowDao accountFlowDao;

	@Resource
	private CommonIdUtils commonIdUtils;


	@Override
	public AccountInfoVO openAccount(OpenAccountReq req) throws Exception {
		final String OP = "AccountInfoServiceImpl.openAccount";

		// 1.业务检查
		checkBusiness(req);

		AccountInfo accountInfo = buildAccountInfo(req);
		// 唯一约束冲突标识位
		boolean duplicateKeyFlag = false;
		try {
			// 2.开户
			accountInfoDao.insert(accountInfo);
		} catch (DuplicateKeyException e) {
			logger.error(Log.op(OP).msg("唯一约束冲突").kv("req", req).toString(), e);
			duplicateKeyFlag = true;
		}

		// 唯一约束冲突,两种情况 1.重复开户，幂等成功 2.用户id已存在或者存管账户号已存在，但是不匹配，这种抛出异常
		if (duplicateKeyFlag) {
			AccountInfo existAccount = accountInfoDao.queryAccountInfoByUniqueKey(accountInfo.getUserId(), accountInfo.getDepositAccountNo(),
					accountInfo.getAccountNo());
			if (existAccount == null) { // 插入失败,报唯一约束冲突异常,没有查到信息，向上层报系统异常
				throw AccountExceptionCode.SYS_ERROR.exp();
			}

			if (accountInfo.getAccountNo().equals(existAccount.getAccountNo())) {// 账户编号唯一索引冲突,系统错误;
				throw AccountExceptionCode.SYS_ERROR.exp();
			}

			if (accountInfo.getUserId().equals(existAccount.getUserId())
					&& !accountInfo.getDepositAccountNo().equals(existAccount.getDepositAccountNo())) {// user_id唯一索引冲突
				throw AccountExceptionCode.USERID_EXSITS.exp(req.getUserId());
			}

			if (accountInfo.getDepositAccountNo().equals(existAccount.getDepositAccountNo())
					&& !accountInfo.getUserId().equals(existAccount.getUserId())) {// 存管账号冲突
				throw AccountExceptionCode.DEPOSIT_EXSITS.exp(req.getDepositAccountNo());
			}

			accountInfo = existAccount;
		}


		return convertToAccountInfoVo(accountInfo);
	}

	/**
	 * PO转VO
	 *
	 * @param po
	 * @return
	 * @author maojian
	 * @date 2017-05-24 09:51:48
	 * @since v1.0.0
	 */
	private AccountInfoVO convertToAccountInfoVo(AccountInfo po) {
		AccountInfoVO vo = new AccountInfoVO();
		vo.setAccountNo(po.getAccountNo());
		vo.setDepositAccountNo(po.getDepositAccountNo());
		vo.setUserId(po.getUserId());
		vo.setAccountType(po.getAccountType());
		vo.setAmount(po.getAmount());
		vo.setFrozenAmount(po.getFrozenAmount());
		vo.setRemark(po.getRemark());
		return vo;
	}

	/**
	 * 业务检查
	 *
	 * @param req
	 * @author maojian
	 * @date 2017-05-27 08:48:04
	 * @since v1.0.0
	 */
	private void checkBusiness(OpenAccountReq req) {
		if (req.getAccountType().isPlatformAccount()) {
			throw AccountExceptionCode.OPEN_ACCOUNT_TYPE_ERROR.exp();
		}
	}

	/**
	 * 创建用户开户信息
	 *
	 * @param req
	 * @return
	 * @author maojian
	 * @date 2017-05-27 08:48:12
	 * @since v1.0.0
	 */
	private AccountInfo buildAccountInfo(OpenAccountReq req) {
		AccountInfo accountInfoPo = new AccountInfo();
		accountInfoPo.setAccountNo(commonIdUtils.generateId(TableSequenceEnum.ACCOUNT_INFO));
		accountInfoPo.setUserId(req.getUserId());
		accountInfoPo.setAccountName(req.getUserName());
		accountInfoPo.setDepositAccountNo(req.getDepositAccountNo());
		accountInfoPo.setCreateTime(DateUtil.getCurrentDateTime());
		accountInfoPo.setUpdateTime(accountInfoPo.getCreateTime());
		accountInfoPo.setRemark(req.getRemark() == null ? "" : req.getRemark());
		accountInfoPo.setAccountType(req.getAccountType().getCode());
		accountInfoPo.setLoginPwd(req.getLoginPwd());
		accountInfoPo.setDrawPwd(req.getDrawPwd());
		return accountInfoPo;
	}

	@Override
	public List<OpenAccountRsp> openAccountBatch(BatchOpenAccountReq params) throws Exception {
		final String op = "AccountInfoServiceImpl.openAccountBatch";
		logger.info(Log.op(op).msg("批量开户开始").toString());
		List<OpenAccountRsp> list = Lists.newArrayList();

		List<OpenAccountReq> reqs = params.getList();
		for (OpenAccountReq openAccountReq : reqs) {
			OpenAccountRsp rsp;
			try {
				AccountInfoVO openAccount = openAccount(openAccountReq);
				rsp = OpenAccountRsp.newInstance(openAccount.getUserId(), openAccount.getAccountNo(), YesNoEnum.YES.getValue(), "成功");
			} catch (Exception e) {
				logger.error(Log.op(op).msg("批量开户，开户异常").kv("userId", openAccountReq.getUserId()).toString(), e);
				rsp = OpenAccountRsp.newInstance(openAccountReq.getUserId(), "", YesNoEnum.NO.getValue(), e.getMessage());
			}

			list.add(rsp);
		}

		logger.info(Log.op(op).msg("批量开户结束").toString());

		return list;
	}

}
